<?php
/**
 * 迭代器
 * 提供一种方法来访问聚合对象,而不暴露这个对象的类部表示
 *
 * 我的理解:
 * 1. 对聚合数据的遍历 和 对聚合数据的管理 是两种不同的业务
 * 2. 对聚合数据的遍历 , 需要 next  current valid key    等操作
 * 3. 对聚合数据的管理 , 只需要 add  remove update delete
 * 4. 迭代器可以将这两种不同的业务分离开 , 通过构建一个具体的替代器实例来完成对聚合数据的操作
 * 5. 其实就是将当前的聚合数据注入到对应的迭代器中 , 让迭代器来操作遍历
 * */

class Student{
    protected $name = '';
    public function __construct($name)
    {
        $this->name = $name;
    }

    public function getName(){
        return $this->name . PHP_EOL;
    }
}

class StudentList implements IteratorAggregate {
    protected $StudentArray = [];

    public function add($student){
        $this->StudentArray[] = $student;
    }

    public function getStudentArray(){
        return $this->StudentArray;
    }
    /**
     * 返回迭代器,用于访问类部聚合
     * */
    public function getIterator()
    {
        return new StudentListIterator($this);
    }

}

/**
 * 学生列表迭代器
 * */
class StudentListIterator implements Iterator{
    /**
     * @var StudentList $studentList
     * */
    private $studentList;
    private $key = 0;

    public function __construct(StudentList $studentList)
    {
        $this->studentList = $studentList->getStudentArray();
    }

    /**
     * @inheritDoc
     * @return Student
     */
    public function current()
    {
        return $this->studentList[$this->key];
    }

    /**
     * @inheritDoc
     */
    public function next()
    {
        $this->key ++;
    }

    /**
     * @inheritDoc
     */
    public function key()
    {
        return $this->key;
    }

    /**
     * @inheritDoc
     */
    public function valid()
    {
        return isset($this->studentList[$this->key]);
    }

    /**
     * @inheritDoc
     */
    public function rewind()
    {
        $this->key = 0;
    }
}

$studentList = new StudentList();
$studentList->add(new Student('王大锤'));
$studentList->add(new Student('王二锤'));
$studentList->add(new Student('王三锤'));
$studentList->add(new Student('王四锤'));
$studentList->add(new Student('王五锤'));

$iterator = $studentList->getIterator();

while ($iterator->valid()) {
    echo $iterator->current()->getName();
    $iterator->next();
}